package com.wen.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * jwt工具类
 */
@Component
@NoArgsConstructor
@Slf4j
@ConfigurationProperties(prefix = "devin.jwt")
//@PropertySource("classpath:base.properties")
public class JwtUtil {
    /*
     * 执行的操作'不依赖'于其它类的单个特征，请将其设置为静态
     * */
    /**
     * 密钥
     */
    private String secret;// 可以用 用户的密码作为密钥
    /**
     * 过期时间 / 单位 （秒）
     */
    private long expireTimeProp;

    private String header;

    /**
     * 生成jwt token
     * <p>
     * iss: jwt签发者
     * sub: jwt所面向的用户 //这个以后就是放我们登录的用户名
     * aud: 接收jwt的一方
     * exp: jwt的过期时间，这个过期时间必须要大于签发时间 //过期时间也可以放
     * nbf: 定义在什么时间之前，该jwt都是不可用的.
     * iat: jwt的签发时间
     * jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击
     */
    public String generateJwt(long userId) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expireTimeProp * 1000);
        log.info("issuedAt: {} , expireTime: {}", nowDate, expireDate);
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(userId + "")
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public String sign(String username, String secret) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expireTimeProp * 1000);

        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(username)
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public Claims getClaimByJwt(String jwt) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (Exception e) {
            log.error("token验证失败 {}", e.getMessage());
            return null;
        }
    }

    /**
     * 验证jwt
     *
     * @param token
     * @param secret
     * @return
     */
    public Claims verifyJwt(String jwt, String secret) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("verifyToken failed {}", e.getMessage());
            return null;
        }
    }

    /**
     * 时间是否过期
     *
     * @return true：过期
     */
    public boolean isExpired(Date expiration) {
        return expiration.before(new Date());
    }

    /**
     * 获取 jwt 的过期时间
     *
     * @param jwt 要查看过期时间的 Token 字符串
     * @return 过期时间的 Date 对象
     */
    public Date getExpirationDate(String jwt) {
        Claims claims = getClaimByJwt(jwt);
        if (claims != null) {
            return claims.getExpiration();
        }
        return null;
    }

    /**
     * 获取jwt的签发时间
     * @param jwt
     * @return
     */
    public Date getIssuedAt(String jwt) {
        Claims claims = getClaimByJwt(jwt);
        if (claims != null) {
            return claims.getIssuedAt();
        }
        return null;
    }

    /**
     * 判断 Jwt 是否过期
     *
     * @param jwt 要判断是否过期的 Jwt 字符串
     * @return true 表示已过期，false 表示未过期
     */
    public boolean isJwtExpired(String jwt) {
        Date expirationDate = getExpirationDate(jwt);
        if (expirationDate != null) {
            return expirationDate.before(new Date());
        }
        return true;
    }

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public long getExpireTimeProp() {
        return expireTimeProp;
    }

    public void setExpireTimeProp(long expireTimeProp) {
        this.expireTimeProp = expireTimeProp;
    }

    public String getHeader() {
        return header;
    }

    public void setHeader(String header) {
        this.header = header;
    }
}